package com.free.bsf.health.collect;

import com.carrotsearch.sizeof.RamUsageEstimator;
import com.free.bsf.core.base.Ref;
import com.free.bsf.core.common.Collector;
import com.free.bsf.core.util.PropertyUtils;
import com.free.bsf.health.base.AbstractCollectTask;
import com.free.bsf.health.base.FieldReport;

import com.free.bsf.health.memoryParse.DoubtApiInterceptor;
import com.free.bsf.health.memoryParse.MemoryRecordUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.val;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 收集使用内存最大的前五个接口及内存使用情况
 * 
 * @author Robin.Wang
 * @date 2019-10-23
 * @version 1.0.0
 */
public class MemoryParseCollectTask extends AbstractCollectTask {

	@Override
	public int getTimeSpan() {
		return PropertyUtils.getPropertyCache("bsf.health.memoryParse.timeSpan", 10);
	}

	@Override
	public boolean getEnabled() {
		return PropertyUtils.getPropertyCache("bsf.health.memoryParse.enabled", false);
	}

	@Override
	public String getDesc() {
		return "内存分析采集";
	}

	@Override
	public String getName() {
		return "memoryParse.info";
	}

	@Override
	protected Object getData() {
		MemoryParseInfo info = new MemoryParseInfo();
		info.doubtDetail=doubtParse();
		Ref<Long> phantomCount = new Ref<>( 0L);
		val phantomReport = MemoryRecordUtils.getPhantomReport(phantomCount);
		info.referenceEntityDetail=getDetail(phantomReport);
		info.referenceCount=phantomCount.getData();
		info.referenceMax=(phantomReport.size()>0?phantomReport.get(0).getValue():0L);
		info.referenceMemorySize=(double)RamUsageEstimator.sizeOf(MemoryRecordUtils.getReferenceHashMap())/1024/1024;

		Ref<Long> requestCount = new Ref<>( 0L);
		val requestReport = MemoryRecordUtils.getRequestReport(requestCount);
		info.requestEntityDetail=getDetail(requestReport);
		info.requestCount=requestCount.getData();
		info.requestMax=(requestReport.size()>0?requestReport.get(0).getValue():0L);
		return info;
	}



	private String getDetail(List<Map.Entry<String,Long>> report){
		StringBuilder memoryDetail = new StringBuilder();
		for(val kv:report){
			memoryDetail.append(kv.getKey()+"["+kv.getValue()+"]\r\n");
		}
		return memoryDetail.toString();
	}

	private String doubtParse(){

		try {
			val map = (Map<String, DoubtApiInterceptor.DoubtApiInfo>) Collector.Default.value("bsf.doubtapi.info").get();
			if (map != null && map.size() > 0) {
				val copy = map.values().toArray(new DoubtApiInterceptor.DoubtApiInfo[map.values().size()]);
				Arrays.sort(copy);
				int detailLen = copy.length > 5 ? 5 : copy.length;
				StringBuilder sb = new StringBuilder();
				for (int i = 0; i < detailLen; i++) {
					val o = copy[i];

					long avg=0;
					if(o.getCount()>0) {
						avg= o.getTotalIncreMem() / 1024 / 1024/ o.getCount();
					}else {
						avg=o.getTotalIncreMem()/ 1024 / 1024;
					}
					sb.append(String.format("url:%s,方法:%s,平均内存增量:%s(M),调用次数:%s\r\n", o.getUri(), o.getMethod(),
							avg, o.getCount()));
				}
				return sb.toString();
			}
		} catch (Exception exp) {
		}
		return "";
	}

	@Data
	@NoArgsConstructor
	@AllArgsConstructor
	public static class MemoryParseInfo {
		@FieldReport(name = "memory.parse.doubt.api.detail", desc = "可疑内存增长api分析报告")
		String doubtDetail;
		@FieldReport(name = "memory.parse.request.entity.detail", desc = "当前所有web请求线程实体内存分析报告")
		String requestEntityDetail;
		@FieldReport(name = "memory.parse.request.entity.total", desc = "当前所有web请求线程实体总个数")
		Long requestCount;
		@FieldReport(name = "memory.parse.request.entity.max", desc = "当前所有web请求线程实体最大个数")
		Long requestMax;
		@FieldReport(name = "memory.parse.reference.entity.detail", desc = "当前所有引用实体内存分析报告")
		String referenceEntityDetail;
		@FieldReport(name = "memory.parse.reference.entity.total", desc = "当前所有引用实体总个数")
		Long referenceCount;
		@FieldReport(name = "memory.parse.reference.entity.max", desc = "当前所有引用实体最大个数")
		Long referenceMax;
		@FieldReport(name = "memory.parse.reference.entity.memorySize", desc = "当前所有引用实体内存大小(M)")
		Double referenceMemorySize;
	}

}
